#include "log.h"
#include "gps.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>


//命令解析响应码
#define AEP_CMD_SUCCESS 0						//执行成功
#define AEP_CMD_FAILED 1						//执行失败
#define AEP_CMD_INVALID_DATASET_TYPE 2			//无效数据集类型
#define AEP_CMD_INVALID_DATASET_IDENTIFIER 3	//无效数据集标识
#define AEP_CMD_PAYLOAD_PARSING_FAILED 4		//指令数据集Payload解析失败,紧凑二进制编码内容长度不符等


#define AEP_BIG_ENDIAN 'b'
#define AEP_LITTLE_ENDIAN 'l'

static union { char c[4]; unsigned long mylong; } endian_test = {{ 'l', '?', '?', 'b' } };
#define AEP_ENDIANNESS ((char)endian_test.mylong)


typedef struct AepStrStruct
{
	unsigned short len;
	char* str;
} AepString;
typedef AepString AepBytes;

typedef struct CmdStruct 
{
	char* serviceIdentifier;
	unsigned short taskId;
	unsigned short serviceId;
	void * data;
	int code;
} AepCmdData;


//无符号整型16位  
uint_16 aep_htons(uint_16 source);

//无符号整型32位
uint_32 aep_htoni(uint_32 source);

//无符号整型64位
uint_64 aep_htonl(uint_64 source);

//float
float aep_htonf(float source);

//double
double aep_htond(double source);

//16进制转字符串
void HexToStr(char *pbDest, char *pbSrc, int nLen);

//字符串转16进制
void StrToHex(char *pbDest, char *pbSrc, int nLen);




//无符号整型16位  
uint_16 aep_htons(uint_16 source)  
{  

	if(AEP_ENDIANNESS == AEP_BIG_ENDIAN)
		return source;
	else
		return (uint_16)( 0
		| ((source & 0x00ff) << 8)
		| ((source & 0xff00) >> 8) );  
}  

//无符号整型32位
uint_32 aep_htoni(uint_32 source)  
{  
	if(AEP_ENDIANNESS == AEP_BIG_ENDIAN)
		return source;
	else
		return 0
		| ((source & 0x000000ff) << 24)
		| ((source & 0x0000ff00) << 8)
		| ((source & 0x00ff0000) >> 8)
		| ((source & 0xff000000) >> 24);  
}

//无符号整型64位
uint_64 aep_htonl(uint_64 source)  
{  
	if(AEP_ENDIANNESS == AEP_BIG_ENDIAN)
		return source;
	else
		return 0
		| ((source & (uint_64)(0x00000000000000ff)) << 56)
		| ((source & (uint_64)(0x000000000000ff00)) << 40)
		| ((source & (uint_64)(0x0000000000ff0000)) << 24)
		| ((source & (uint_64)(0x00000000ff000000)) << 8)
		| ((source & (uint_64)(0x000000ff00000000)) >> 8)
		| ((source & (uint_64)(0x0000ff0000000000)) >> 24)
		| ((source & (uint_64)(0x00ff000000000000)) >> 40)
		| ((source & (uint_64)(0xff00000000000000)) >> 56);
}

//float
float aep_htonf(float source)  
{  
	if(AEP_ENDIANNESS == AEP_BIG_ENDIAN)
		return source;
	else
	{
		uint_32 t= 0
			| ((*(uint_32*)&source & 0x000000ff) << 24)
			| ((*(uint_32*)&source & 0x0000ff00) << 8)
			| ((*(uint_32*)&source & 0x00ff0000) >> 8)
			| ((*(uint_32*)&source & 0xff000000) >> 24);
		return *(float*)&t;
	} 
}

//double
double aep_htond(double source)  
{  
	if(AEP_ENDIANNESS == AEP_BIG_ENDIAN)
		return source;
	else
	{
		uint_64 t= 0
			| ((*(uint_64*)&source & (uint_64)(0x00000000000000ff)) << 56)
			| ((*(uint_64*)&source & (uint_64)(0x000000000000ff00)) << 40)
			| ((*(uint_64*)&source & (uint_64)(0x0000000000ff0000)) << 24)
			| ((*(uint_64*)&source & (uint_64)(0x00000000ff000000)) << 8)
			| ((*(uint_64*)&source & (uint_64)(0x000000ff00000000)) >> 8)
			| ((*(uint_64*)&source & (uint_64)(0x0000ff0000000000)) >> 24)
			| ((*(uint_64*)&source & (uint_64)(0x00ff000000000000)) >> 40)
			| ((*(uint_64*)&source & (uint_64)(0xff00000000000000)) >> 56);
		return *(double*)&t;
	}
}

//track report
int track_report_DecodeCmdDown (char* source, track_report* dest)
{
	char* index = source;
	int srcStrLen = strlen(source);
	int len = 25;


	memset(dest, 0, sizeof(track_report));

	StrToHex((char *)&dest->gps_enable, index, 1);
	//dest->gps_enable = aep_htoni(dest->gps_enable);
	index += 1 * 2;

	
	debugf("track_report_DecodeCmdDown gps_enable:%d \r\n",dest->gps_enable);

	StrToHex((char *)&dest->longitude, index, 4);
	dest->longitude = aep_htonf(dest->longitude);
	index += 4 * 2;

	debugf("track_report_DecodeCmdDown dest->longitude:%f \r\n",dest->longitude);
	
	StrToHex((char *)&dest->latitude, index, 4);
	dest->latitude = aep_htonf(dest->latitude);
	index += 4 * 2;

	debugf("track_report_DecodeCmdDown dest->latitude:%f \r\n",dest->latitude);

	StrToHex((char *)&dest->altitude, index, 4);
	dest->altitude = aep_htonf(dest->altitude);
	index += 4 * 2;
	debugf("track_report_DecodeCmdDown dest->altitude:%f \r\n",dest->altitude);

	StrToHex((char *)&dest->speed, index, 4);
	dest->speed = aep_htoni(dest->speed);
	index += 4 * 2;	
	debugf("track_report_DecodeCmdDown dest->speed:%d \r\n",dest->speed);

	StrToHex((char *)&dest->direction, index, 4);
	dest->direction = aep_htoni(dest->direction);
	index += 4 * 2;	
	debugf("track_report_DecodeCmdDown dest->direction:%d \r\n",dest->direction);

	StrToHex((char *)&dest->stamp, index, 4);
	dest->stamp = aep_htoni(dest->stamp);
	index += 4 * 2;		
	debugf("track_report_DecodeCmdDown dest->stamp:%d \r\n",dest->stamp);

	if (len * 2 > srcStrLen)
	{
		return AEP_CMD_PAYLOAD_PARSING_FAILED;
	}
	return AEP_CMD_SUCCESS;
}





//字符串转16进制
void StrToHex(char *pbDest, char *pbSrc, int nLen)
{
	unsigned char h1,h2;
	unsigned char s1,s2;
	int i;

	for (i=0; i<nLen; i++)
	{
		h1 = pbSrc[2*i];
		h2 = pbSrc[2*i+1];

		s1 = toupper(h1) - 0x30;
		if (s1 > 9) 
			s1 -= 7;

		s2 = toupper(h2) - 0x30;
		if (s2 > 9) 
			s2 -= 7;

		pbDest[i] = s1*16 + s2;
	}
}


AepCmdData decodeCmdDownFromStr(char* source)
{
	char* index;
	AepCmdData result;
	char cmdType;
	unsigned short serviceId;
	unsigned short payloadLen;

	debugf("decodeCmdDownFromStr:%s",source);
	memset(&result, 0, sizeof(AepCmdData));

	index = source;


	//解析包头
	if ((*(index) != 'A')||(*(index+1) != 'T'))
	{
		result.code = AEP_CMD_INVALID_DATASET_TYPE;
		debugf("decodeCmdDownFromStr A1");
		return result;
	}
	index +=  2;

	

	//服务Id解析
	StrToHex((char *)&serviceId, index, 2);
	serviceId = aep_htons(serviceId);
	index += 2 * 2;
	debugf("decodeCmdDownFromStr serviceId:%d ",serviceId);


	//payload长度解析
	StrToHex((char *)&payloadLen, index, 2);
	payloadLen = aep_htons(payloadLen);
	index += 2 * 2;

	debugf("decodeCmdDownFromStr payloadLen:%d ",payloadLen);

	if (strlen(index) < payloadLen * 2)
	{
		result.code = AEP_CMD_PAYLOAD_PARSING_FAILED;
		return result;
	}


	if (serviceId == 1)
	{
		debugf("decodeCmdDownFromStr A2");
		result.serviceId = serviceId;
		result.serviceIdentifier = "track_report";
		result.data = malloc(sizeof(track_report));
		memset(result.data, 0, sizeof(track_report));
		result.code = track_report_DecodeCmdDown(index, (track_report*)result.data);
	}
	else 
	{
		result.serviceId = 0;
		result.serviceIdentifier = NULL;
		result.data = malloc(payloadLen);
		memset(result.data, 0, sizeof(payloadLen));
		StrToHex((char *)result.data, index, payloadLen);
		result.code = AEP_CMD_INVALID_DATASET_IDENTIFIER;
	}

	return result;
}

track_report decodeGps(const char* data){
	AepCmdData cmd = decodeCmdDownFromStr(data);
	track_report report = {0};
	if(cmd.serviceId == 1){
		memcpy(&report,cmd.data,sizeof(track_report));
		free(cmd.data);
	}
	return report;
}